package org.maxgroundstation.groundstation.comm.service;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * Abstract class for a MAX robot service.
 * @author Scott Davis
 * 
 * Copyright (C) 2010  Scott Davis
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
public abstract class Service {

	// Data members
	private ServiceCommunication comm;
	private String name;
	private String format;
	private String description;
	private Map<String, String> parameters;
	private ConcurrentLinkedQueue<ServiceListener> listeners;
	
	/**
	 * Constructor.
	 * @param comm the service communication.
	 */
	public Service(ServiceCommunication comm) {
		this.comm = comm;
		name = "";
		this.format = "";
		this.description = "";
		this.parameters = new HashMap<String, String>();
		listeners = new ConcurrentLinkedQueue<ServiceListener>();
	}
	
	/**
	 * Gets the service communication.
	 * @return service communication.
	 */
	public ServiceCommunication getServiceCommunication() {
		return comm;
	}
	
	/**
	 * Gets the unique service ID.
	 * @return service ID.
	 */
	public abstract String getID();
	
	/**
	 * Checks if service is a default service.
	 * @return true if default service.
	 */
	public abstract boolean isDefaultService();
	
	/**
	 * Checks if service can be subscribed to.
	 * @return true if service can be subscribed to.
	 */
	public abstract boolean isSubscribable();
	
	/**
	 * Initializes the service.
	 */
	public abstract void initialize();
	
	/**
	 * Closes down the service.
	 */
	public void closeDown() {
	    // Remove all listeners.
	    listeners.clear();
	}
	
	/**
	 * Gets the service response format.
	 * @return format.
	 */
	public String getFormat() {
		return format;
	}
	
	/**
	 * Sets the service response format.
	 * @param format the format.
	 */
	public void setFormat(String format) {
		this.format = format;
	}
	
	/**
	 * Gets the service name.
	 * @return the service name.
	 */
	public String getName() {
		return name;
	}
	
	/**
	 * Sets the service name.
	 * @param name the service name.
	 */
	public void setName(String name) {
		this.name = name;
	}
	
	/**
	 * Gets the service description.
	 * @return service description.
	 */
	public String getDescription() {
		return description;
	}
	
	/**
	 * Sets the description.
	 * @param description the description.
	 */
	public void setDescription(String description) {
		this.description = description;
	}
	
	/**
	 * Gets the map of parameter keys and values.
	 * @return map of parameter keys and values.
	 */
	public Map<String, String> getParameters() {
		return parameters;
	}
	
	/**
	 * Sets the map of parameter keys and values.
	 * @param parameters map of parameter keys and values.
	 */
	public void setParameters(Map<String, String> parameters) {
		this.parameters = parameters;
	}
	
	/**
	 * Handles a data frame response for the service.
	 * @param dataFrame the response data frame.
	 */
	public abstract void handleResponse(ServiceDataFrame dataFrame);
	
    /**
     * Adds a service listener.
     * @param listener the service listener.
     */
    public void addServiceListener(ServiceListener listener) {
        if ((listener != null) && !listeners.contains(listener)) listeners.add(listener);
    }
    
    /**
     * Removes a service listener.
     * @param listener the service listener.
     */
    public void removeServiceListener(ServiceListener listener) {
        if (listeners.contains(listener)) listeners.remove(listener);
    }
    
    /**
     * Fires a service event of a given type.
     * @param eventType the event type.
     */
    public final void fireServiceEvent(String eventType) {
        fireServiceEvent(eventType, null);   
    }
    
    /**
     * Fires a service event of a given type and target object.
     * @param eventType the event type.
     * @param target the target object.
     */
    public final void fireServiceEvent(String eventType, Object target) {
        ServiceEvent event = new ServiceEvent(this, eventType, target);
        Iterator<ServiceListener> i = listeners.iterator();
        while (i.hasNext()) i.next().serviceUpdate(event);
    }
    
    /**
     * Gets the service type.
     * @return service type string.
     */
    public abstract String getType();
}